3-1 gRPC服务健康检查:扩展health.proto
为什么需要 gRPC 原生健康检查
之前的健康检查方案是通过独立的 RESTful 端口(如 3000/3001)暴露 HTTP 接口。这种方式的缺点:
| 问题 | 说明 |
|---|---|
| 端口浪费 | 每个微服务需要同时占用 gRPC 端口和 HTTP 端口 |
| 配置复杂 | Consul 注册时需要配置额外的 HTTP 健康检查地址 |
| 不够标准 | HTTP 健康检查不适用于纯 gRPC 服务 |
更好的方案是直接通过 gRPC 协议进行健康检查,省去 RESTful 端口。
创建 health.proto
在 proto-pkg/proto/ 目录下创建 health.proto:
syntax = "proto3";
package health;
// 健康检查服务
service HealthService {
rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
}
message HealthCheckRequest {
string service = 1;
}
message HealthCheckResponse {
uint32 status = 1;
}
protobuf
设计说明
| 字段 | 类型 | 说明 |
|---|---|---|
HealthCheckRequest.service | string | 要检查的服务名称 |
HealthCheckResponse.status | uint32 | 健康状态码(1 = 健康) |
在微服务 proto 中引入 health.proto
方式一:在现有 service 中添加 Check 方法
在 user.proto 中 import health.proto 并扩展:
syntax = "proto3";
package user;
import "health.proto"; // 引入公共健康检查定义
service UserService {
// 原有的业务方法
rpc FindOne(UserId) returns (UserResponse) {}
// ...
// 健康检查方法(使用 health 包中的类型)
rpc Check(health.HealthCheckRequest) returns (health.HealthCheckResponse);
}
protobuf
注意:由于 HealthCheckRequest 和 HealthCheckResponse 定义在 health 包中,引用时需要加包名前缀 health.。
方式二:定义独立的 HealthService
syntax = "proto3";
package user;
import "health.proto";
// 业务服务
service UserService {
rpc FindOne(UserId) returns (UserResponse) {}
}
// 独立的健康检查服务
service HealthService {
rpc Check(health.HealthCheckRequest) returns (health.HealthCheckResponse);
}
protobuf
代码生成配置调整
由于引入了外部 proto 文件,代码生成命令需要添加 -I 参数指定 proto 搜索路径:
{
"scripts": {
"generate:user": "grpc_tools_node_protoc \
-I ./proto \
--js_out=import_style=commonjs,binary:./src/generated/user \
--grpc_out=grpc_js:./src/generated/user \
--ts_proto_out=./src/nest/user \
./proto/user.proto"
}
}
json
-I ./proto 参数告诉 protoc 在 ./proto 目录下查找被 import 的 proto 文件。如果不添加此参数,会报 health.proto: File not found 错误。
生成结果验证
代码生成完成后,检查输出文件:
src/nest/user/
├── user.ts # UserService 相关类型和接口
└── health.ts # HealthService 相关类型和接口
src/generated/user/
├── user_grpc_pb.js # UserService gRPC 客户端/服务端
├── user_pb.js # UserService 消息类型
├── health_grpc_pb.js # HealthService gRPC 客户端/服务端
└── health_pb.js # HealthService 消息类型
text
生成文件中会包含:
| 内容 | 说明 |
|---|---|
HealthServiceControllerMethods | 装饰器,自动绑定 Check 方法到 gRPC |
HealthServiceController | 接口定义,包含 check 方法签名 |
HealthCheckRequest | 请求消息类 |
HealthCheckResponse | 响应消息类 |
入口文件改造
微服务入口改为纯 gRPC 模式,不再需要 RESTful 端口:
// 改造前:同时创建 gRPC + RESTful
const app = await NestFactory.create(AppModule);
await app.listen(3000);
const microservice = app.connectMicroservice<MicroserviceOptions>({...});
await app.startAllMicroservices();
// 改造后:纯 gRPC 微服务
const app = await NestFactory.createMicroservice<MicroserviceOptions>({
transport: Transport.GRPC,
options: {
package: ['user', 'health'],
protoPath: [join(__dirname, '../proto/user.proto')],
url: '0.0.0.0:40001',
},
});
await app.listen();
typescript
好处:每个微服务只需要一个 gRPC 端口,节省端口资源,配置更简洁。
参考资源
- gRPC Health Checking Protocol - gRPC 官方健康检查协议
- Protocol Buffers proto3 - proto3 语法
- grpc-tools - 代码生成工具
↑